package dinnerSimulation;

import java.util.Random;


/**
 * 
 * This class implement an environment that interact with the vacuum-cleaner agent.
 * 
 * @see AbstractAgent
 * @see Agent
 * 
 *
 */
public class Environment {

	
	public enum Type {
		STATIC,
		DYNAMIC_1,
		DYNAMIC_2,
		DYNAMIC_3
	}
	
	
//	public Agent agent;
	public AgentCiccio agent;
	
	public Action.Type currAction;
	public Type type;
	public Floor floor;
	public Coord n_flowers_pos;
	public Coord n_suit_pos;
	public int k;
	public boolean start;

	private Coord n_table_pos;
	
	//public Environment(int length, int width, Agent agent, Environment.Type dynType){
	public Environment(int length, int width, AgentCiccio agent, Environment.Type dynType){

		this.floor = new Floor(length, width, Square.Type.CLEAN);
		
		this.agent = agent;
		
		this.type = dynType;
		
		this.k = 1;
		this.start = false;
		
		
	}
	
	//public Environment(int length, int width, Agent agent, Environment.Type dynType){
		public Environment(int width, AgentCiccio agent, Environment.Type dynType){

			this.floor = new Floor(width);
			
			this.agent = agent;
			
			this.type = dynType;
			
			this.k = 1;
			
			this.start = false;
		}
		

	/**
	 * 
	 *  Set the perceptions according with the agent visibility.
	 *
	 * 		If agent's visibility is MY_CELL, just the state of cell where the agent is located,
	 * 		will be add to the perception.
	 *		If agent's visibility is MY_NEIGHBOURS, the state of cell where the agent is located
	 *		and the 8 cells in its Moore neighborhood will be add to the perception.
	 *		If agent's visibility is ALL, all the cells will be add to the perception.
	 * 	
	 * 		
	 * 
	 * @return  the current perception 
	 * 
	 * @see Perception
	 */
	public Perception getPerceptions() {
		/* create a perception with a floor of unknown state */
		Perception perception = new Perception(new Floor(floor.length,floor.width, Square.Type.CLEAN));
		/* then add informations according to the agent visibility */
	
				/* add informations according to the agent visibility.*/
		/*ciccio pasticcio 'vede' tutto*/
		for(int i=0; i<floor.length; i++)
			for(int j=0; j<floor.width; j++){
				perception.floor.set(i, j, floor.get(i, j));
			}
		for(int j=0; j<floor.length; j++)
			perception.floor.room[j] = floor.room[j];
		
		//perception.floor.set(agent.x, agent.y, floor.get(agent.x, agent.y));
		return perception;
	}

	/**
	 * Update the environment state according to the action performed by the agent
	 */

	
	public void changePos(Square.Type obj, Coord obj_pos){
		int new_pos;
		if(obj_pos.getX()!=-1 && obj_pos.getY()!=-1){
			
		
			
		Random rand = new Random();

		do {
			new_pos = Math.abs(rand.nextInt()) % floor.width;
		} while (!floor.get(obj_pos.getX(), new_pos).equals(Square.Type.CLEAN));
		

		
		floor.set(obj_pos.x, new_pos, obj);

		//System.out.println("L'oggetto : "+ obj.toString() +
		//		" � stato spostato in room " +  obj_pos.x + " pos " + new_pos );
		
			if (obj.equals(Square.Type.FLOWERS)) { // aggiorna le posizioni
													// degli oggetti
				n_flowers_pos = new Coord(obj_pos.x, new_pos);
				floor.set(obj_pos.x, obj_pos.y, Square.Type.CLEAN);
			} else if(obj.equals(Square.Type.SMOKING)){
				n_suit_pos = new Coord(obj_pos.x, new_pos);
				floor.set(obj_pos.x, obj_pos.y, Square.Type.CLEAN);
			}else{
				n_table_pos = new Coord(obj_pos.x, new_pos);
				floor.set(obj_pos.x, obj_pos.y, Square.Type.CLEAN);
			}
				
			
				}else{
			System.out.println("Oggetto "+ obj.toString()+" non presente");
			
			if (obj.equals(Square.Type.FLOWERS)) { // aggiorna le posizioni degli oggetti
																	
				n_flowers_pos = new Coord(-1, -1);
			} else if(obj.equals(Square.Type.SMOKING)) {
				n_suit_pos = new Coord(-1, -1);
			}else 
				n_table_pos = new Coord(-1, -1);
		}
		
		
		
	}
	

	public void changePosD3(Square.Type obj, Coord obj_pos){
		int new_posX, new_posY;
		
		
		if(obj_pos.getX()>=0 && obj_pos.getY()>=0){
			
		
			
		Random rand = new Random();
		do {
			new_posY = Math.abs(rand.nextInt()) % floor.width;
			new_posX = Math.abs(rand.nextInt()) % (floor.length-1);
		} while (!floor.get(new_posX, new_posY).equals(Square.Type.CLEAN));
		

		
		floor.set(new_posX, new_posY, obj);

		System.out.println("L'oggetto : "+ obj.toString() +
				" � stato spostato da " +  obj_pos.x + " - " + obj_pos.y + "a pos " + new_posX + " - " + new_posY );
		
			if (obj.equals(Square.Type.FLOWERS)) { // aggiorna le posizioni
													// degli oggetti
				n_flowers_pos = new Coord(new_posX, new_posY);
				floor.set(obj_pos.x, obj_pos.y, Square.Type.CLEAN);
			}
			
			if(obj.equals(Square.Type.SMOKING)){
				n_suit_pos = new Coord(new_posX, new_posY);
				floor.set(obj_pos.x, obj_pos.y, Square.Type.CLEAN);
			}
			
			if(obj.equals(Square.Type.TABLE)){
				n_table_pos = new Coord(new_posX, new_posY);
				floor.set(obj_pos.x, obj_pos.y, Square.Type.CLEAN);
			}
				
			
		}else{
			System.out.println("Oggetto "+ obj.toString()+" non presente");
			
			if (obj.equals(Square.Type.FLOWERS) && agent.FLOWERS_TAKEN)  // aggiorna le posizioni degli oggetti
																	
				n_flowers_pos = new Coord(-1, -1);
			
			
			
			if(obj.equals(Square.Type.SMOKING) && agent.SUIT_UP) 
				n_suit_pos = new Coord(-1, -1);
			
			//if(obj.equals(Square.Type.TABLE))			
			//	n_table_pos = new Coord(-1, -1);
		}
		
		
		
	}

	public void update() {

		if (!start) {
			System.out.println("first update");
			n_suit_pos = floor.search(Square.Type.SMOKING);
			n_flowers_pos = floor.search(Square.Type.FLOWERS);
			n_table_pos = floor.search(Square.Type.TABLE);
			start = true;
		}
		k = k + 1; // ad ogni chiamata di update si incrementa k
		
		agent.perceives(getPerceptions());
		// Point cp = this.floor.search(vacuumCleaner.Square.Type.CICCIO);
		// agent.setCurrentPosition(cp.x+1, cp.y+1);
		agent.update();
		getAction(agent.action());
		System.out.println("Action received: " + currAction);

		if (type.equals(Environment.Type.DYNAMIC_1)) {
			dynamic_1();
		}
		if (type.equals(Environment.Type.DYNAMIC_2)) {
			dynamic_2();
		}
		if (type.equals(Environment.Type.DYNAMIC_3)) {
			dynamic_3();
		}
		if (currAction == Action.Type.DRESS_UP) {
			n_suit_pos = new Coord(-1, -1);
			agent.setSUIT_UP(true);
			System.out.println("SMOKING in -1 -1");
			Coord smPos = floor.search(Square.Type.SMOKING);
			floor.set(smPos.x, smPos.y, dinnerSimulation.Square.Type.CLEAN);
			
			

		}
		if (currAction == Action.Type.PREPARE_MEAL) {
			System.out.println("Environment prepare meal");
			agent.setMEAL_READY(true);
			// agent.goalReached=true;
			// floor.set(agent.x, agent.y, vacuumCleaner.Square.Type.CLEAN);
		}

		if (currAction == Action.Type.TABLE_READY) {
			agent.setTABLE_READY(true);
			// floor.set(agent.x, agent.y, vacuumCleaner.Square.Type.CLEAN);
		}

		if (currAction == Action.Type.TAKE_MEAL) {
			agent.setTAKE_MEAL(true);
			floor.set(agent.x, agent.y, dinnerSimulation.Square.Type.CLEAN);

		}

		if (currAction == Action.Type.TAKE_FLOWERS) {
			agent.setFLOWERS_TAKEN(true);
			System.out.println("FLOWERS in -1 -1");
			Coord flPos = floor.search(Square.Type.FLOWERS);
			floor.set(flPos.x, flPos.y, dinnerSimulation.Square.Type.CLEAN);
			
			n_flowers_pos = new Coord(-1, -1);

		}

		// floor.set(agent.x, agent.y, vacuumCleaner.Square.Type.CLEAN);

		if (currAction == Action.Type.WAIT_RENATA) {
			agent.setENTRANCE(true);
			agent.goalReached = true;
			floor.set(agent.x, agent.y, Square.Type.END);

		}

		if (currAction == Action.Type.NORTH)
			agent.x--;
		if (currAction == Action.Type.SOUTH)
			agent.x++;
		if (currAction == Action.Type.EAST)
			agent.y++;
		if (currAction == Action.Type.WEST)
			agent.y--;

	}
	

	public void getAction(Action.Type action) {
		currAction = action;
	}
	
	public float performanceMeasure(){
	
		int step = agent.stepValue();
		float numOp = agent.actionList.size(); // numero azioni
		float numCel = floor.length * floor.width;
		
		float perc_op = (numOp/numCel)/100;
		
		float bonus = 0;
		float result= 0;
		
		if(agent.isMEAL_READY())	bonus+=20;
		if(agent.isSUIT_UP()) 		bonus+=20;
		if(agent.isTABLE_READY())	bonus+=20;
		if(agent.isFLOWERS_TAKEN()) bonus+=20;
		if(agent.isENTRANCE()) 		bonus+=20;
		
		result = (bonus/100) - perc_op;

		return result;
	}
	
	public String toString(){
		StringBuffer sb = new StringBuffer();
		for(int i=0; i<floor.length; i++){
			for(int j=0; j<floor.width; j++)
				if(agent.x == i && agent.y == j)
					sb.append("AGENT ");
				else
					if(floor.get(i, j) == Square.Type.FLOWERS)
						sb.append("-FLOW ");
					else if(floor.get(i, j) == Square.Type.SMOKING)
						sb.append("-SMOK ");
				else
					sb.append("----- ");
			sb.append("\n");
		}
		return sb.toString();
	}
	
	public void show(){
		System.out.println(this);
	}
	
	public void dynamic_1(){
		System.err.println(" Dentro environment DINAMIC_1");
		System.err.println("agent.kValue " + agent.kValue  + " k " + k );
		if (this.k == agent.kValue) { // scegli un oggetto tra fiori // vestito e spostalo
			System.out.println("K " + k);
			this.k = 1;
			Random rand = new Random();
			int random = Math.abs(rand.nextInt()) % 2;

			if (!agent.cal_suitUp && !agent.MEAL_READY) {
				if (random == 1)
					changePos(Square.Type.SMOKING, n_suit_pos);
				else
					changePos(Square.Type.FLOWERS, n_flowers_pos);

			}else if (agent.cal_suitUp && !agent.cal_takeFlow)

				changePos(Square.Type.FLOWERS, n_flowers_pos);
		}
		
	}
	
	public void dynamic_2(){
		System.err.println(" Dentro environment DINAMIC_2");
		System.err.println("agent.kValue " + agent.kValue  + " k " + k );
		if (this.k == agent.kValue) { // scegli un oggetto tra fiori // vestito e spostalo
			System.out.println("K " + k);
			this.k = 1;

			if (!agent.cal_suitUp) {
				
					changePos(Square.Type.SMOKING, n_suit_pos);
					changePos(Square.Type.FLOWERS, n_flowers_pos);
					changePos(Square.Type.TABLE, n_table_pos);
			}
			else if (agent.cal_suitUp && !agent.cal_table_ready) {
				changePos(Square.Type.FLOWERS, n_flowers_pos);
				changePos(Square.Type.TABLE, n_table_pos);
			}
			if(agent.cal_table_ready && !agent.cal_takeFlow)
				changePos(Square.Type.FLOWERS, n_flowers_pos);
		
	}
	
}

	public void dynamic_3(){
		System.err.println(" Dentro environment DINAMIC_3");
		System.err.println("agent.kValue " + agent.kValue  + " k " + k );
		if (this.k == agent.kValue) { // scegli un oggetto tra fiori // vestito e spostalo
			System.out.println("K " + k);
			this.k = 1;

			if (!agent.cal_suitUp && !agent.MEAL_READY) {
				
					changePosD3(Square.Type.SMOKING, n_suit_pos);
					changePosD3(Square.Type.FLOWERS, n_flowers_pos);
					changePosD3(Square.Type.TABLE, n_table_pos);
			}
			else if (agent.cal_suitUp && !agent.TAKE_MEAL) {
				changePosD3(Square.Type.FLOWERS, n_flowers_pos);
				changePosD3(Square.Type.TABLE, n_table_pos);
			}
			
			if(agent.cal_table_ready && !agent.cal_takeFlow)
				changePosD3(Square.Type.FLOWERS, n_flowers_pos);
		
	}
	
}





}
